'use strict';
const axios = require('axios');
const { getSongFileName } = require('decrypt-tracks');
const { existsSync, mkdirsSync } = require('fs-extra');
const nodePath = require('path');
const deezerApi = require('deezer-request2');
const musicQualities = require('../musicQualities');
const sanitize = require('sanitize-filename');
const signale = require('signale');

/**
 * Capitalizes the first letter of a string
 *
 * @param {String} string
 *
 * @returns {String}
 */
const capitalizeFirstLetter = (string) => {
  return string.charAt(0).toUpperCase() + string.slice(1);
};

/**
 * Remove whitespaces and special characters from the given string.
 *
 * @param {String} string
 */
const removeWhitespacesAndSpecialChars = (string) => {
  return string.replace(/[^A-Z0-9]/gi, '');
};

/**
 * Check if certain music quality exist
 *
 * @param {Object} trackInfos
 * @param {Number} quality
 *
 * @returns {String}
 */

const isFileExists = async (trackInfos, quality, fileSize) => {
  if (Number(fileSize) > 1024) {
    return fileSize;
  }

  const downloadUrl = getTrackDownloadUrl(trackInfos, quality);
  try {
    const { headers } = await axios.head(downloadUrl);
    return headers['content-length'];
  } catch (err) {
    return null;
  }
};

/**
 * Get a downloadable track quality.
 *
 * FLAC -> 320kbps -> 128kbps
 * 320kbps -> 128kbps
 * 128kbps -> Error
 *
 * @param {Object} trackInfos
 * @param {Number} quality
 *
 * @returns {Object}
 */
const getValidTrackQuality = async (trackInfos, quality) => {
  const { MP3_MISC, FLAC, MP3_320, MP3_128 } = musicQualities.qualities;

  // User uploaded song
  if (trackInfos.FILESIZE_MP3_MISC === '0') {
    return MP3_MISC;
  }

  // If FLAC exists use FLAC otherwise fallback to MP3_320
  if (FLAC.id === quality) {
    if (await isFileExists(trackInfos, quality, trackInfos.FILESIZE_FLAC)) {
      return FLAC;
    }
    signale.warn(`FLAC is not available for "${trackInfos.SNG_TITLE}". Falling back to 320kbps.`);
    // Fallback to 320kbps
    quality = MP3_320.id;
  }

  // If MP3_320 exists use MP3_320 otherwise fallback to MP3_128
  if (MP3_320.id === quality) {
    if (await isFileExists(trackInfos, quality, trackInfos.FILESIZE_MP3_320)) {
      return MP3_320;
    }
    signale.warn(`320kbps is not available for "${trackInfos.SNG_TITLE}". Falling back to 128kbps.`);
  }

  // Return 128kbps id
  if (Number(trackInfos.FILESIZE_MP3_128) > 1024) {
    return MP3_128;
  }
};

/**
 * Get infos of an album by id.
 *
 * @param {Number} id
 */
const getAlbumInfos = async (id) => {
  try {
    let { data } = await deezerApi.getAlbumTrackInfo(id);
    if (Object.keys(data.error).length === 0 && data.results) {
      return data.results;
    } else {
      return null;
    }
  } catch (err) {
    return null;
  }
};

/**
 * Replaces multiple whitespaces with a single one.
 *
 * @param {String} string
 * @returns {String}
 */
const multipleWhitespacesToSingle = (string) => {
  return string.replace(/[ _,]+/g, ' ');
};

/**
 * Replaces multiple whitespaces with a single one.
 *
 * @param {String} fileName
 * @returns {String}
 */
const sanitizeFilename = (fileName) => {
  fileName = fileName.replace('/', '-');
  return sanitize(fileName);
};

/**
 * Adds a zero to the beginning if the number has only one digit.
 *
 * @param {Number} number
 * @returns {String}
 */
const toTwoDigits = (number) => {
  return (number < 10 ? '0' : '') + number;
};

/**
 * Calculate the URL to download the track.
 *
 * @param {Object} trackInfos
 * @param {Number} trackQuality
 *
 * @returns {String}
 */
const getTrackDownloadUrl = (trackInfos, trackQuality) => {
  const cdn = trackInfos.MD5_ORIGIN[0];
  return 'http://e-cdn-proxy-' + cdn + '.deezer.com/mobile/1/' + getSongFileName(trackInfos, trackQuality);
};

/**
 * Create directories of the given path if they don't exist.
 *
 * @param {String} filePath
 * @return {boolean}
 */
const ensureDir = (filePath) => {
  const dirName = nodePath.dirname(filePath) + nodePath.sep;
  if (!existsSync(dirName)) {
    mkdirsSync(dirName);
  }
  return dirName;
};

module.exports = {
  capitalizeFirstLetter,
  removeWhitespacesAndSpecialChars,
  getValidTrackQuality,
  getAlbumInfos,
  multipleWhitespacesToSingle,
  sanitizeFilename,
  toTwoDigits,
  getTrackDownloadUrl,
  ensureDir,
};
